﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using MkvSplicer.Video;

namespace MkvSplicer
{
    public partial class MainForm : Form
    {
        private MkvHandler handler;

        public MainForm()
        {
            InitializeComponent();
            encodePresets.SelectedIndex = 0;
        }

        private List<string> parseSplits()
        {
            string input = timecodeSplits.Text.Replace(" ", "");
            char[] comma = { ',' }, dash = { '-' };
            string[] splitPairs = input.Split(comma, 
                    StringSplitOptions.RemoveEmptyEntries);
            List<string> invalidSplits = new List<String>();

            handler.clearSplits();
            foreach (string splitPair in splitPairs)
            {
                string[] splitBoundaries = splitPair.Split(dash,
                    StringSplitOptions.RemoveEmptyEntries);
                if (splitBoundaries.Length != 2)
                    invalidSplits.Add(splitPair);
                else
                {
                    try
                    {
                        handler.addSplit(splitBoundaries[0], splitBoundaries[1]);
                    }
                    catch (FormatException)
                    {
                        invalidSplits.Add(splitPair);
                    }
                }
            }

            input = frameSplits.Text.Replace(" ", "");
            splitPairs = input.Split(comma,
                StringSplitOptions.RemoveEmptyEntries);
            
            foreach (string splitPair in splitPairs)
            {
                string[] splitBoundaries = splitPair.Split(dash,
                    StringSplitOptions.RemoveEmptyEntries);
                if (splitBoundaries.Length != 2)
                    invalidSplits.Add(splitPair);
                else
                {
                    try
                    {
                        long start = long.Parse(splitBoundaries[0]);
                        long end = long.Parse(splitBoundaries[1]);
                        handler.addSplit(start, end);
                    }
                    catch (FormatException)
                    {
                        invalidSplits.Add(splitPair);
                    }
                }
            }

            return invalidSplits;
        }

        private void processSplits(FileInfo baseFileOut, string x264Params)
        {
            using (SplitOutput output = new SplitOutput(handler, baseFileOut, x264Params))
            {
                output.ShowDialog();
            }
        }

        private void updateInputFile(String strFileIn)
        {
            FileInfo fileIn = new FileInfo(strFileIn);

            using (ProgressIndicator progress = new ProgressIndicator(fileIn))
            {
                DialogResult ret = progress.ShowDialog();
                if (ret == DialogResult.OK)
                {
                    handler = progress.Handler;
                    inputFileLocation.Text = fileIn.FullName;
                    fileOutPath.Text = Path.Combine(fileIn.Directory.FullName, Path.GetFileNameWithoutExtension(fileIn.FullName) + "-split.mkv");
                    fileInfo.Text = handler.VideoInfo;
                    encodeSettings_Changed(this, null); //Fire change
                }
                else
                {
                    fileInfo.Text = null; //Clear fields
                    overallEncode.Text = null;
                    handler = null;
                    inputFileLocation.Text = null;
                    fileOutPath.Text = null;
                }
            }
        }

        #region events
        private void inputFileBrowse_MouseClick(object sender, MouseEventArgs e)
        {
            DialogResult result = inputFileDialog.ShowDialog(this);
            if (result == DialogResult.OK)
            {
                updateInputFile(inputFileDialog.FileName);
            } //Input file dialogue
        }

        private void handleSplits_Click(object sender, EventArgs e)
        {
            if (handler != null)
            {
                List<string> invalidSplits = parseSplits();
                if (invalidSplits.Count > 0)
                {
                    string invalids = String.Join(", ", invalidSplits);
                    MessageBox.Show(this, "The following splits were invalid:\r\n" +
                        invalids + "\r\nPlease fix these before continuing.",
                        "Invalid splits", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    return;
                }

                if (handler.Splits.Count > 0)
                {
                    string splitInfo = String.Join("\r\n", handler.Splits);
                    if (sender == getSplits)
                    {
                        MessageBox.Show(this, "The splits were parsed as such:\r\n" +
                            splitInfo, "Split info", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                    else //This is an actual split event!
                    {
                        //Validate other parameters
                        FileInfo fileOut;
                        
                        try {
                            fileOut = new FileInfo(fileOutPath.Text);
                            if (fileOut.Exists && (fileOut.Attributes & FileAttributes.Directory) != 0) {
                                throw new Exception("Output cannot be a directory");
                            }
                        } catch (Exception ex) {
                            MessageBox.Show(this, "The output file path is invalid:\r\n" +
                                ex.Message, "Invalid output file",
                                MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            return;
                        }

                        //Ensure up-to-date settings
                        encodeSettings_Changed(this, null);
                        if (String.IsNullOrWhiteSpace(overallEncode.Text))
                        {
                            MessageBox.Show(this,
                                "Invalid encode settings specified.",
                                null, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                            return;
                        }

                        DialogResult ret = MessageBox.Show(this,
                            "The following splits will be processed:\r\n" +
                            splitInfo + "\r\nContinue?", "Split confirmation",
                            MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
                        if (ret == DialogResult.OK)
                        { //Do it
                            processSplits(fileOut, overallEncode.Text);
                        }
                    }
                }
            }
            else
            {
                MessageBox.Show(this, "Select an input file first.", "No input file selected",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }
        #endregion //Events

        private void outputBrowse_Click(object sender, EventArgs e)
        {
            DialogResult ret = saveFileDialog.ShowDialog();
            if (ret == DialogResult.OK)
            {
                fileOutPath.Text = saveFileDialog.FileName;
            }
        }

        private void encodeSettings_Changed(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            overallEncode.Text = null;
            if (handler == null)
                return;

            if (inputIsLossless.Checked)
                sb.Append(" --qp 0");
            else
                sb.Append(" --crf 20");

            if (!matchEncode.Checked)
            {
                int spsId;
                try
                {
                    spsId = int.Parse(spsIdText.Text);
                }
                catch (Exception)
                {
                    spsId = 1;
                }

                sb.Append(" --sps-id ").Append(spsId);
            }
            sb.Append(" --output-csp ").Append(handler.Colourspace);

            switch (encodePresets.SelectedIndex)
            {
                case 1: //HQ
                    sb.Append(" --preset veryslow"); 
                    if (!inputIsLossless.Checked)
                        sb.Append(" --crf 16"); break;
                case 2: //HQ anime
                    sb.Append(" --preset veryslow --tune animation"); 
                    if (!inputIsLossless.Checked)
                        sb.Append(" --crf 16"); break;
            }
            sb.Append(" ").Append(reencodeParams.Text);

            if (matchEncode.Checked)
                sb.Append(handler.EncodeSettings);

            overallEncode.Text = sb.ToString();
        }

        private void matchEncode_CheckedChanged(object sender, EventArgs e)
        {
            if (handler != null)
            {
                if (matchEncode.Checked && String.IsNullOrEmpty(handler.EncodeSettings))
                {
                    MessageBox.Show(this,
                        "This mode is not possible because the previous encode" + 
                        " settings could not be detected.",
                        null, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                    matchEncode.Checked = false;
                    return;
                }
                encodeSettings_Changed(sender, e);
            }
        }

        private void MainForm_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Move;
            else
                e.Effect = DragDropEffects.None;
        }

        private void MainForm_DragDrop(object sender, DragEventArgs e)
        {
            String[] s = e.Data.GetData(DataFormats.FileDrop) as String[];
            updateInputFile(s[0]);
        }
    } //MainForm
}
